package com.thinkingcoder.tcgateway.plugin;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.server.ServerWebExchange;

import com.thinkingcoder.tcgateway.plugin.chain.GatewayPluginChain;
import com.thinkingcoder.tcrpc.core.balancer.LoadBalancer;
import com.thinkingcoder.tcrpc.core.balancer.RoundRobinLoadBalancer;
import com.thinkingcoder.tcrpc.core.meta.InstanceMeta;
import com.thinkingcoder.tcrpc.core.meta.ServiceMeta;
import com.thinkingcoder.tcrpc.core.registry.RegistryCenter;

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@Component("tcRpc")
public class TcRpcPlugin extends AbstractGatewayPlugin {

    private final static String NAME = "TcRpc-Plugin";
    private final static String CONTEXT = "tcrpc";

    @Autowired
    private RegistryCenter registryCenter;

    LoadBalancer<InstanceMeta> loadBalancer = new RoundRobinLoadBalancer<>();

    @Override
    public String getName() {
        return NAME;
    }

    @Override
    public String getContext() {
        return CONTEXT;
    }

    @Override
    public boolean doSupport(ServerWebExchange exchange) {
        return exchange.getRequest().getPath().value().startsWith(getPrefix());
    }

    @Override
    public Mono<Void> doHandle(ServerWebExchange exchange, GatewayPluginChain chain) {
        System.out.println(" ===>>> [TcRpcPlugin] ...");

        // 1. 通过请求路径获取服务明
        String service = exchange.getRequest().getPath().value().substring(getPrefix().length());
        ServiceMeta serviceMeta =
            ServiceMeta.builder().name(service).app("app1").env("dev").namespace("public").build();

        // 2. 通过 RegistyCenter 获取所有活着的实例
        List<InstanceMeta> instanceMetas = registryCenter.fetchAll(serviceMeta);
        InstanceMeta choose = loadBalancer.choose(instanceMetas);
        System.out.println("instance size = " + instanceMetas.size() + " , instance" + choose);

        // 3. 按照规则，获取真实请求路径
        String url = choose.toUrl();

        // 4. 拿到真实请求的报文
        Flux<DataBuffer> requestBody = exchange.getRequest().getBody();
        // 5. 通过 WebClient 发送 post 请求
        WebClient client = WebClient.create(url);
        Mono<ResponseEntity<String>> entity = client.post().contentType(MediaType.APPLICATION_JSON)
            .body(requestBody, DataBuffer.class).retrieve().toEntity(String.class);

        // 6. 通过 entity 获取响应报文
        // entity.map(temp -> temp.getBody()); 简化后 entity.map(ResponseEntity::getBody);
        Mono<String> body = entity.map(ResponseEntity::getBody);

        // 7. 组装响应报文
        exchange.getResponse().getHeaders().add("Content-Type", "application/json");
        exchange.getResponse().getHeaders().add("tc.gateway.version", "v1.0.0");
        exchange.getResponse().getHeaders().add("tc.gateway.plugin", getName());

        return body.flatMap(x -> {
            System.out.println(x);
            return exchange.getResponse()
                .writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(x.getBytes())))
                .then(chain.handle(exchange));
        });
    }

}
